home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 11
/
CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso
/
cucd
/
programming
/
oberonv4
/
source
/
system
/
opv.mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1996-06-09
|
29KB
|
880 lines
Syntax10.Scn.Fnt
StampElems
Alloc
9 Jun 96
FoldElems
Syntax10.Scn.Fnt
PROCEDURE f1():REAL;
BEGIN
RETURN 8
END f1;
PROCEDURE Do*;
BEGIN
f:=f1;
w:=f(); Out.Real(w,8);
w:=f1(); Out.Real(w,8);
END Do;
MODULE OPV;
(* Control Module for the backend of the Oberon-2-Compiler for Sun-3.
Diplomarbeit Samuel Urech
Date: 30.10.92 Current version:
Try to fix a bug in Expr. Hope it will work. RD 17.4.96
had problems
Added SYSTEM.CALL (*<<OJ*) *)
IMPORT OPT, OPC, OPL, OPM;
CONST
(* object modes *)
Var = 1; VarPar = 2; Con = 3; Fld = 4; Typ = 5; LProc = 6; XProc = 7;
SProc = 8; CProc = 9; IProc = 10; Mod = 11; Head = 12; TProc = 13;
(* opcodes *)
ASh = 0; LSh = 1; ROt = 3;
(* Condition codes *)
false = 1; true = 0;
CC = 4; CS = 5; EQ = 7; GE = 12; GT = 14; HI = 2; LE = 15;
LS = 3; LT = 13; MI = 11; NE = 6; PL = 10; VC = 8; VS = 9;
(* operation node subclasses *)
times = 1; slash = 2; div = 3; mod = 4;
and = 5; plus = 6; minus = 7; or = 8; eql = 9;
neq = 10; lss = 11; leq = 12; gtr = 13; geq = 14;
in = 15; is = 16; ash = 17; msk = 18; len = 19;
conv = 20; abs = 21; cap = 22; odd = 23; not = 33;
(* SYSTEM *)
adr = 24; cc = 25; bit = 26; lsh = 27; rot = 28; val = 29;
(* structure forms *)
Undef = 0; Byte = 1; Bool = 2; Char = 3; SInt = 4; Int = 5; LInt = 6;
Real = 7; LReal = 8; Set = 9; String = 10; NilTyp = 11; NoTyp = 12;
Pointer = 13; ProcTyp = 14; Comp = 15;
(* composite structure forms *)
Basic = 1; Array = 2; DynArr = 3; Record = 4;
intSet = { SInt, Int, LInt }; realSet = { Real, LReal };
(* node classes *)
Nvar = 0; Nvarpar = 1; Nfield = 2; Nderef = 3; Nindex = 4; Nguard = 5; Neguard = 6;
Nconst = 7; Ntype = 8; Nproc = 9; Nupto = 10; Nmop = 11; Ndop = 12; Ncall = 13;
Ninittd = 14; Nif = 15; Ncaselse = 16; Ncasedo = 17; Nenter = 18; Nassign = 19;
Nifelse =20; Ncase = 21; Nwhile = 22; Nrepeat = 23; Nloop = 24; Nexit = 25;
Nreturn = 26; Nwith = 27; Ntrap = 28;
(* function numbers *)
assign = 0; newfn = 1; incfn = 13; decfn = 14;
inclfn = 15; exclfn = 16; copyfn = 18; assertfn = 32;
(* SYSTEM function numbers *)
getfn = 24; putfn = 25; getrfn = 26; putrfn = 27; sysnewfn = 30; movefn = 31; callfn = 33; (*<<OJ*)
VarParSize = OPM.PointerSize;
RecVarParSize = 2 * OPM.PointerSize;
ProcOff = 8;
(* procedure flags *)
hasBody = 1; isRedef = 2;
(* accessibility of objects *)
internal = 0; external = 1; externalR = 2;
(* trap numbers *)
WithTrap = 15;
CaseTrap = 16;
FuncTrap = 17;
VAR assert, findpc, typCheck : BOOLEAN;
loopEnd : OPL.Label;
PROCEDURE Init*( opt : SET; bpc : LONGINT );
CONST ass = 7; fpc = 8; typchk = 3;
BEGIN
typCheck := typchk IN opt;
assert := ass IN opt;
findpc := fpc IN opt;
IF findpc THEN OPM.breakpc := bpc ELSE OPM.breakpc := MAX( LONGINT ) END
END Init;
PROCEDURE Base( typ : OPT.Struct ) : INTEGER;
(* Returns the alignment of a type. *)
BEGIN
WHILE typ.comp = Array DO typ := typ.BaseTyp END;
IF typ.form IN { Byte, Bool, Char, SInt } THEN RETURN 1
ELSE RETURN 2
END
END Base;
PROCEDURE Align( VAR adr : LONGINT; base : LONGINT );
(* Aligns the given address with the given base. *)
BEGIN
IF adr > 0 THEN
INC( adr, ( -adr ) MOD base );
ELSE
DEC( adr, adr MOD base );
END;
END Align;
PROCEDURE ^TypSize*( typ : OPT.Struct; dummy : BOOLEAN );
PROCEDURE ParamAdr( par : OPT.Object; VAR psize : LONGINT );
(* Calculates the sizes of the parameters of a procedure and returns their sum in psize. *)
VAR typ : OPT.Struct;
c : INTEGER;
BEGIN (* ParamAdr *)
WHILE par # NIL DO
typ := par.typ; c := typ.comp;
TypSize( typ, FALSE );
IF par.mode = VarPar THEN
par.adr := psize;
IF c = Record THEN INC( psize, RecVarParSize )
ELSIF c = DynArr THEN INC( psize, typ.size )
ELSE INC( psize, VarParSize )
END;
ELSE
IF typ.form IN {Byte, Bool, Char, SInt, Int} THEN
INC( psize, OPM.LIntSize );
ELSE
INC( psize, typ.size );
END;
par.adr := psize - typ.size;
par.linkadr := par.adr;
END; (* IF *)
Align( psize, 4 ); (* all parameters are aligned to 4 bytes. *)
par := par.link;
END; (* WHILE *)
END ParamAdr;
PROCEDURE ^VarAdr( var : OPT.Object; VAR dsize : LONGINT );
PROCEDURE ^Traverse( obj : OPT.Object; exported : BOOLEAN );
PROCEDURE ProcSize( obj : OPT.Object; firstpass : BOOLEAN );
(* Writes the size of the local variables into the field obj.conval.intval and calculates the addresses of all parameters. *)
VAR oldPos : LONGINT;
conval: OPT.Const;
typ : OPT.Struct;
redef : OPT.Object;
BEGIN (* ProcSize *)
conval := obj.conval;
oldPos := OPM.errpos;
OPM.errpos := obj.scope.adr;
IF ( ( obj.vis # internal ) = firstpass ) OR ( obj.mode = TProc ) THEN
obj.adr := -1;
obj.linkadr := OPL.NewLabel;
IF obj.mode IN { XProc, IProc, TProc } THEN
IF OPL.entno < OPL.MaxEntry THEN
obj.adr := OPL.entno;
INC( OPL.entno );
ELSE
OPM.err( 226 );
obj.adr := 1;
END;
END;
IF obj.mnolev > 0 THEN
conval.intval2 := ProcOff + OPM.PointerSize; (* for static link *)
ELSE
conval.intval2 := ProcOff;
END;
ParamAdr( obj.link, conval.intval2 );
IF obj.mode = TProc THEN
typ := obj.link.typ;
IF typ.form = Pointer THEN typ := typ.BaseTyp END;
OPT.FindField( obj.name, typ.BaseTyp, redef );
IF redef # NIL THEN
obj.adr := 10000H * ( redef.adr DIV 10000H ) (* mthno *) + obj.adr (* entno *);
IF ~( isRedef IN obj.conval.setval ) THEN OPM.err( 134 ) END;
ELSE
INC( obj.adr, 10000H * typ.n );
INC( typ.n );
END; (* IF *)
END; (* IF *)
END; (* IF *)
IF ~firstpass THEN
IF ~( hasBody IN conval.setval ) THEN OPM.err( 129 ) END;
conval.intval := 0;
VarAdr( obj.scope.scope, conval.intval ); (* local variables *)
Traverse( obj.scope.right, FALSE ); (* local types and procedures *)
END;
OPM.errpos := oldPos
END ProcSize;
PROCEDURE TypSize*( typ : OPT.Struct; dummy : BOOLEAN );
(* Writes the size of a type into typ.size. All subordinate type sizes are calculated, all record fields get an offset. *)
VAR offset, size : LONGINT;
fld : OPT.Object;
btyp : OPT.Struct;
BEGIN (* TypSize *)
IF typ.size = -1 THEN
CASE typ.form OF
Pointer :
typ.size := OPM.PointerSize;
IF typ.BaseTyp = OPT.undftyp THEN
OPM.Mark( 128, typ.n );
ELSE
TypSize( typ.BaseTyp, FALSE );
END;
| ProcTyp :
size := ProcOff; typ.size := OPM.ProcSize;
ParamAdr( typ.link, size ); (* inserts the addresses of the parameters. *)
| Comp :
CASE typ.comp OF
Record :
btyp := typ.BaseTyp;
IF btyp = NIL THEN
offset := 0;
ELSE
TypSize( btyp, FALSE );
offset := btyp.size;
END;
fld := typ.link;
WHILE ( fld # NIL ) & ( fld.mode = Fld ) DO
btyp := fld.typ;
TypSize( btyp, FALSE );
size := btyp.size;
Align( offset, Base( btyp ) );
fld.adr := offset;
INC( offset, size );
fld := fld.link
END; (* WHILE *)
Align( offset, 2 ); (* all records are at least 2 Bytes long *)
typ.size := offset;
| Array :
TypSize( typ.BaseTyp, FALSE );
typ.size := typ.n * typ.BaseTyp.size;
| DynArr :
btyp := typ.BaseTyp;
IF typ.offset < 0 THEN typ.offset := typ.n; END;
IF btyp.comp = DynArr THEN btyp.offset := typ.n; END;
TypSize( btyp, FALSE );
IF btyp.comp = DynArr THEN
typ.size := btyp.size + 4;
ELSE
typ.size := 8;
END;
END; (* CASE *)
ELSE (* nothing *)
END; (* CASE typ.form *)
END; (* IF *)
END TypSize;
PROCEDURE VarAdr( var : OPT.Object; VAR dsize : LONGINT );
(* Inserts entry-numbers and addresses into the variables. Exported variables are entered into the entry list. *)
VAR typ: OPT.Struct; adr: LONGINT;
BEGIN
adr := -dsize;
WHILE var # NIL DO
typ := var.typ;
TypSize( typ, FALSE );
DEC( adr, typ.size );
IF typ.form = Comp THEN
Align( adr, 4 );
ELSE
Align( adr, Base( typ ) );
END; (* IF *)
IF var.vis = internal THEN
var.adr := adr;
ELSE
OPL.SetEntry( OPL.entno, adr );
var.adr := OPL.entno;
INC( OPL.entno );
END; (* IF *)
var.linkadr := adr;
var := var.link
END; (* WHILE *)
dsize := -adr;
Align( dsize, 8 );
END VarAdr;
PROCEDURE Traverse( obj : OPT.Object; exported : BOOLEAN );
(* Completes types and procedures. *)
VAR typ: OPT.Struct;
PROCEDURE TraverseRecord( typ : OPT.Struct );
(* Inserts the type descriptor address into the types and the method numbers into the methods. *)
BEGIN
IF typ.tdadr = OPM.TDAdrUndef THEN
IF typ.BaseTyp # NIL THEN
TraverseRecord( typ.BaseTyp );
typ.n := typ.BaseTyp.n;
END; (* IF *)
Traverse( typ.link, FALSE ); (* traverse methods *)
OPL.AllocTypDesc( typ );
END; (* IF *)
END TraverseRecord;
BEGIN (* Traverse *)
IF obj # NIL THEN
Traverse( obj.left, exported );
IF ( obj.mode = Typ ) & ( ( obj.vis # internal ) = exported ) THEN
typ := obj.typ;
TypSize( typ, FALSE );
IF typ.form = Pointer THEN typ := typ.BaseTyp END;
IF typ.comp = Record THEN TraverseRecord( typ ) END;
ELSIF obj.mode IN {LProc, XProc, TProc, CProc, IProc} THEN
ProcSize( obj, exported )
END ;
Traverse( obj.right, exported )
END
END Traverse;
PROCEDURE AdrAndSize*;
(* Completes the symbol table: types, variables, record-fields and procedures. *)
BEGIN (* AdrAndSize *)
OPL.dsize := 0;
VarAdr( OPT.topScope.scope, OPL.dsize );
OPM.errpos := OPT.topScope.adr; (* text position of the scope *)
Traverse( OPT.topScope.right, TRUE ); (* first run for all exported types and procedures *)
Traverse( OPT.topScope.right, FALSE ); (* second run for all local types and procedures *)
END AdrAndSize;
PROCEDURE BaseTyp( typ : OPT.Struct ) : OPT.Struct;
(* Returns the record type belonging to typ. *)
BEGIN (* BaseTyp *)
IF typ.form = Pointer THEN RETURN typ.BaseTyp
ELSE RETURN typ
END
END BaseTyp;
PROCEDURE ^Expr( node : OPT.Node; VAR res : OPL.Item );
PROCEDURE Designator( node : OPT.Node; VAR res : OPL.Item );
(* Returns an item for a designator. res.mode is in { regx, pcx }. *)
VAR index, tag : OPL.Item;
BEGIN (* Designator *)
CASE node.class OF
Nvar, Nvarpar :
OPC.MakeVar( node.obj, res );
| Nfield :
Designator( node.left, res );
OPC.MakeField( res, node.obj.adr, node.typ );
| Nderef :
Designator( node.left, res );
OPC.DeRef( node.typ, res );
| Nindex :
Expr( node.right, index );
Designator( node.left, res );
OPC.MakeIndex( index, res );
| Nguard, Neguard :
Designator( node.left, res );
IF typCheck THEN
OPC.saveRegs:=FALSE;
OPC.MakeTag( node.left.obj, node.left.typ, res, tag );
OPC.TypeTest( tag, BaseTyp( node.typ ), TRUE, node.class = Neguard );
OPC.saveRegs:=TRUE;
END; (* IF *)
| Nproc :
OPC.MakeProc( node.obj, node.subcl, res );
END; (* CASE *)
res.typ := node.typ;
END Designator;
PROCEDURE AllocParams( formalPar : OPT.Object; VAR psize : LONGINT );
(* Allocates space on the stack for the parameters and increments psize by their size. *)
BEGIN (* AllocParams *)
WHILE formalPar # NIL DO
IF formalPar.mode = VarPar THEN
IF formalPar.typ.comp = Record THEN INC( psize, RecVarParSize )
ELSIF formalPar.typ.comp = DynArr THEN INC( psize, formalPar.typ.size )
ELSE INC( psize, VarParSize )
END;
ELSE
INC( psize, formalPar.typ.size );
END; (* IF *)
Align( psize, 4 );
formalPar := formalPar.link;
END; (* WHILE *)
OPC.AddToSP( -psize );
END AllocParams;
PROCEDURE AssignParams( formalPar : OPT.Object; actualPar : OPT.Node );
(* Moves the actual parameters to the stack. *)
VAR par, par1, tag : OPL.Item;
BEGIN (* AssignParams *)
WHILE formalPar # NIL DO
IF formalPar.typ.comp = DynArr THEN
Expr( actualPar, par );
OPC.MoveDynArrStack( formalPar.typ, formalPar.adr - ProcOff, par );
ELSIF formalPar.mode = VarPar THEN
Designator( actualPar, par );
par1 := par;
OPC.MoveAdrStack( formalPar.adr - ProcOff, par );
IF formalPar.typ.comp = Record THEN
OPC.MakeTag( actualPar.obj, actualPar.typ, par, tag );
OPC.MoveStack( formalPar.adr + 4 - ProcOff, tag );
ELSIF ( formalPar.typ = OPT.sysptrtyp ) & ( actualPar.typ # OPT.sysptrtyp ) THEN
(* pass static type to enable run time tests *)
OPC.StaticTag( actualPar.typ.BaseTyp, tag );
OPC.Assign( tag, par1 );
ELSIF ( formalPar.typ = OPT.sysptrtyp ) & ( actualPar.typ = OPT.sysptrtyp ) & ( actualPar.obj.mode # VarPar ) THEN
(* pass NIL to disable run time tests *)
OPC.MakeIntConst( 0, OPT.linttyp, tag );
OPC.Assign( tag, par1 );
END; (* IF *)
ELSE
par.tJump := OPL.NewLabel;
par.fJump := OPL.NewLabel;
Expr( actualPar, par );
OPC.Convert( par, formalPar.typ );
OPC.MoveStack( formalPar.adr - ProcOff, par );
END; (* IF *)
OPL.usedRegs := { };
actualPar := actualPar.link;
formalPar := formalPar.link;
END; (* WHILE *)
END AssignParams;
PROCEDURE Expr( node : OPT.Node; VAR res : OPL.Item );
(* Returns an item for the result of an exression. *)
VAR expr1, expr2, expression, set, element, procItem, arr, tag : OPL.Item;
swap : OPL.Label;
savedRegs : SET;
psize: LONGINT;
Dummy: SHORTINT;
BEGIN (* Expr *)
CASE node.class OF
Nconst :
OPC.MakeConst( node.obj, node.conval, node.typ, res );
| Nupto :
Expr( node.left, expr1 );
Expr( node.right, expr2 );
OPC.UpTo( expr1, expr2, res );
| Nmop :
CASE node.subcl OF
not :
swap := res.tJump;
res.tJump := res.fJump;
res.fJump := swap;
Expr( node.left, res );
swap := res.tJump;
res.tJump := res.fJump;
res.fJump := swap;
OPC.Not( res );
| minus :
Expr( node.left, res );
OPC.Neg( res );
| is :
Designator( node.left, res );
tag.tJump := res.tJump;
tag.fJump := res.fJump;
OPC.saveRegs:=FALSE;
OPC.MakeTag( node.left.obj, node.left.typ, res, tag );
OPC.TypeTest( tag, BaseTyp( node.obj.typ ), FALSE, FALSE );
OPC.saveRegs:=TRUE;
res := tag;
| conv :
Expr( node.left, res );
IF node.typ.form = Set THEN
OPC.SetElem( res );
ELSE
OPC.Convert( res, node.typ );
END; (* IF *)
| abs :
Expr( node.left, res );
OPC.Abs( res );
| cap :
Expr( node.left, res );
OPC.Cap( res );
| odd :
Expr( node.left, res );
OPC.Odd( res );
| adr :
Expr( node.left, res );
OPC.Adr( res );
| cc :
OPC.MakeCocItem( SHORT( node.left.conval.intval ), res );
| val :
res.tJump := OPL.NewLabel;
res.fJump := OPL.NewLabel;
Expr( node.left, res );
IF res.typ.comp = DynArr THEN OPC.GetDynArrVal( res ); END;
res.typ := node.typ;
END; (* CASE *)
| Ndop :
CASE node.subcl OF
times :
Expr( node.left, expression );
Expr( node.right, res );
OPC.Mul( node.typ, expression, res );
| slash :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Divide( node.typ, expression, res );
| div :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Div( expression, res );
| mod :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Mod( expression, res );
| and :
savedRegs := OPL.usedRegs;
expression.tJump := OPL.NewLabel;
expression.fJump := res.fJump;
Expr( node.left, expression );
OPC.FalseJump( expression, expression.fJump );
OPL.usedRegs := savedRegs;
Expr( node.right, res );
OPC.Test( res );
res.fJump := OPL.MergedLinks( expression.fJump, res.fJump );
| plus :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Plus( node.typ, expression, res );
| minus :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Minus( node.typ, expression, res );
| or :
savedRegs := OPL.usedRegs;
expression.tJump := res.tJump;
expression.fJump := OPL.NewLabel;
Expr( node.left, expression );
OPC.TrueJump( expression, expression.tJump );
OPL.usedRegs := savedRegs;
Expr( node.right, res );
OPC.Test( res );
res.tJump := OPL.MergedLinks( expression.tJump, res.tJump );
| eql, neq, lss, leq, gtr, geq :
expr1.tJump := OPL.NewLabel;
expr1.fJump := OPL.NewLabel;
expr2.tJump := OPL.NewLabel;
expr2.fJump := OPL.NewLabel;
Expr( node.left, expr1 );
OPC.LoadCC( expr1 );
Expr( node.right, expr2 );
OPC.Compare( node.subcl, expr1, expr2, res );
| in :
Expr( node.left, element );
Expr( node.right, set );
OPC.In( element, set, res );
| ash :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Shift( ASh, expression, res );
| msk :
Expr( node.left, res );
OPC.Mask( -node.right.conval.intval-1, res );
| len :
Designator( node.left, arr );
OPC.MakeLen( arr, node.right.conval.intval, res );
| bit :
Expr( node.left, expr1 );
Expr( node.right, expr2 );
OPC.SYSBit( expr1, expr2, res );
| lsh :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Shift( LSh, expression, res );
| rot :
Expr( node.left, res );
Expr( node.right, expression );
OPC.Shift( ROt, expression, res );
END; (* CASE *)
| Ncall :
savedRegs := OPL.usedRegs;
OPC.PushRegs( OPL.usedRegs );
OPL.usedRegs := { };
IF ( node.left.obj # NIL ) & ( node.left.obj.mode = LProc ) & ( node.left.obj.mnolev > 0 ) THEN
psize := OPM.PointerSize; (* for static link *)
ELSE
psize := 0;
END;
AllocParams( node.obj, psize );
OPC.WriteStaticLink( node.left.obj );
AssignParams( node.obj, node.right );
Designator( node.left, procItem );
OPC.Call( procItem, node.left.obj );
OPC.AddToSP( psize );
OPL.usedRegs := savedRegs;
Dummy:=node.left.typ.form;
node.left.typ.form:=node.typ.form;
OPC.GetResult( node.left.typ, res );
node.left.typ.form:=Dummy;
OPC.PopRegs( savedRegs );
ELSE
Designator( node, res );
END; (* CASE *)
res.typ := node.typ;
END Expr;
PROCEDURE Checkpc;
BEGIN
IF findpc & (OPL.pc > OPM.breakpc) & OPM.noerr THEN OPM.err(255) END
(* in the case of a call, the breakpc value shown in the trap viewer must point to the call instruction
and not to the next instruction, i.e. breakpc # return address !! *)
END Checkpc;
PROCEDURE StatSeq( node : OPT.Node );
(* Generates code for a statement sequence. *)
VAR proc : OPT.Object;
designator, expression, sourceAdr, destAdr, procItem, reg, tag : OPL.Item;
begLabel, savedLoopEnd : OPL.Label;
psize : LONGINT;
PROCEDURE CaseStatement( node : OPT.Node );
(* Generates code for a case statement. *)
VAR expression : OPL.Item;
lo, hi, i, jtAdr : LONGINT;
elseLabel, endLabel : OPL.Label;
case, caseLabel : OPT.Node;
BEGIN (* CaseStatement *)
Expr( node.left, expression );
node := node.right;
lo := node.conval.intval;
hi := node.conval.intval2;
IF hi >= lo THEN
elseLabel := OPL.NewLabel;
endLabel := OPL.NewLabel;
OPC.Case( expression, lo, hi, elseLabel, jtAdr );
FOR i := 0 TO hi - lo DO OPL.ConstWord( SHORT( jtAdr + 2 * i ), OPL.pc DIV 2 ); END;
OPL.DefineLabel( elseLabel );
END; (* IF *)
Checkpc;
IF node.conval.setval = { } THEN
OPC.Trap( CaseTrap );
ELSE
StatSeq( node.right );
END;
IF hi >= lo THEN
case := node.left;
WHILE case # NIL DO
OPL.Jump( true, endLabel );
caseLabel := case.left;
WHILE caseLabel # NIL DO
FOR i := caseLabel.conval.intval - lo TO caseLabel.conval.intval2 - lo DO
OPL.ConstWord( SHORT( jtAdr + 2 * i ), OPL.pc DIV 2 );
END; (* FOR *)
caseLabel := caseLabel.link;
END; (* WHILE *)
StatSeq( case.right );
case := case.link;
END; (* WHILE *)
OPL.DefineLabel( endLabel );
END; (* IF *)
END CaseStatement;
PROCEDURE IfStatement( node : OPT.Node; trap : BOOLEAN );
(* Generates code for an IF-Statement. If trap is true, a Trap is generated in the ELSE-Case. *)
VAR endLabel : OPL.Label;
curNode : OPT.Node;
expression : OPL.Item;
BEGIN (* IfStatement *)
endLabel := OPL.NewLabel;
curNode := node.left;
WHILE curNode # NIL DO
expression.tJump := OPL.NewLabel;
expression.fJump := OPL.NewLabel;
Expr( curNode.left, expression );
OPC.FalseJump( expression, expression.fJump ); Checkpc;
StatSeq( curNode.right );
IF ( curNode.link # NIL ) OR ( node.right # NIL ) OR trap THEN
(* last ELSIF part with no ELSE following *)
OPL.Jump( true, endLabel );
END;
OPL.DefineLabel( expression.fJump );
curNode := curNode.link;
END; (* WHILE *)
IF trap THEN
OPC.Trap( WithTrap );
ELSE
StatSeq( node.right );
END; (* IF *)
OPL.DefineLabel( endLabel );
END IfStatement;
PROCEDURE Size( typ : OPT.Struct; node : OPT.Node; VAR res : OPL.Item );
(* Returns an item that denotes the size of the memory space in bytes that has to be allocated for a dynamic array. *)
VAR dim, offsetItem : OPL.Item;
noflen : INTEGER;
BEGIN (* Size *)
Expr( node, res );
noflen := 1;
node := node.link;
typ := typ.BaseTyp.BaseTyp;
WHILE node # NIL DO
Expr( node, dim );
INC( noflen );
OPC.Mul( OPT.linttyp, dim, res );
node := node.link;
typ := typ.BaseTyp;
END; (* WHILE *)
IF typ.size > 1 THEN
OPC.MakeIntConst( typ.size, OPT.linttyp, dim );
OPC.Mul( OPT.linttyp, dim, res );
END; (* IF *)
OPC.MakeIntConst( 4 * noflen, OPT.linttyp, offsetItem );
OPC.Plus( OPT.linttyp, offsetItem, res );
END Size;
PROCEDURE EnterLengths( VAR item : OPL.Item; node : OPT.Node );
(* Writes the lengths in node to the address in item. Used for NEW( p, len1, len2, ... ). *)
VAR length, adr : OPL.Item;
BEGIN (* EnterLengths *)
adr := item;
OPC.DeRef( OPT.sysptrtyp, adr );
WHILE node # NIL DO
Expr( node, length );
OPC.Convert( length, OPT.linttyp );
OPL.Move( length, adr );
INC( adr.bd, 4 );
node := node.link;
END; (* WHILE *)
END EnterLengths;
PROCEDURE Prepend( s : ARRAY OF CHAR );
(* Writes the given name in parentheses to the reference file. *)
VAR i : INTEGER;
ch : CHAR;
BEGIN (* Prepend *)
i := 0;
ch := s[ 0 ];
OPM.RefW( "(" );
WHILE ch # 0X DO
OPM.RefW( ch );
INC( i );
ch := s[ i ];
END; (* WHILE *)
OPM.RefW( ")" );
END Prepend;
BEGIN (* StatSeq *)
WHILE ( node # NIL ) & OPM.noerr DO
OPM.errpos := node.conval.intval;
OPL.BegStat;
CASE node.class OF
Nenter :
IF node.obj = NIL THEN (* module *)
OPC.EnterMod;
StatSeq( node.right );
OPC.Return( NIL, FALSE, expression );
OPL.OutRefPoint;
OPL.OutRefName( "$" );
OPL.OutRefs( OPT.topScope );
INC( OPL.level );
StatSeq( node.left );
DEC( OPL.level );
ELSE (* procedure *)
proc := node.obj;
INC( OPL.level );
StatSeq( node.left );
DEC( OPL.level );
OPC.EnterProc( proc );
StatSeq( node.right );
IF proc.typ # OPT.notyp THEN OPC.Trap( FuncTrap );
ELSE OPC.Return( proc, FALSE, expression );
END;
OPL.OutRefPoint;
IF proc^.mode = TProc THEN Prepend( proc^.link^.typ^.strobj^.name ) END;
OPL.OutRefName( proc^.name );
OPL.OutRefs( proc^.scope^.right );
END; (* IF *)
| Ninittd :
| Nassign :
CASE node.subcl OF
assign :
expression.tJump := OPL.NewLabel;
expression.fJump := OPL.NewLabel;
Expr( node.right, expression );
OPC.LoadCC( expression );
Designator( node.left, designator );
OPC.Assign( expression, designator );
| newfn :
Designator( node.left, designator );
OPL.LoadAdr( designator );
IF node.right = NIL THEN
IF node.left.typ.BaseTyp.comp = Record THEN
OPC.StaticTag( node.left.typ.BaseTyp, tag );
OPC.New( designator, tag );
ELSE
OPC.MakeIntConst( node.left.typ.BaseTyp.size, OPT.linttyp, expression );
OPC.SYSNew( designator, expression );
END; (* IF *)
ELSE
Size( node.left.typ, node.right, expression );
OPC.SYSNew( designator, expression );
EnterLengths( designator, node.right );
END; (* IF *)
| incfn :
Expr( node.right, expression );
Designator( node.left, designator );
OPL.LoadAdr( designator );
OPC.Increment( designator, expression );
| decfn :
Expr( node.right, expression );
Designator( node.left, designator );
OPL.LoadAdr( designator );
OPC.Decrement( designator, expression );
| inclfn :
Expr( node.right, expression );
Designator( node.left, designator );
OPL.LoadAdr( designator );
OPC.Include( designator, expression );
| exclfn :
Expr( node.right, expression );
Designator( node.left, designator );
OPL.LoadAdr( designator );
OPC.Exclude( designator, expression );
| copyfn :
Expr( node.right, expression );
Designator( node.left, designator );
OPC.Copy( expression, designator );
| getfn :
Expr( node.right, sourceAdr );
Designator( node.left, designator );
OPL.LoadAdr( designator );
OPC.SYSGet( sourceAdr, designator );
| putfn :
Expr( node.left, destAdr );
Expr( node.right, expression );
OPC.SYSPut( expression, destAdr );
| getrfn :
OPC.MakeConst( node.obj, node.right.conval, OPT.inttyp, reg );
Designator( node.left, designator );
OPL.LoadAdr( designator );
OPC.SYSGetReg( designator, reg );
| putrfn :
OPC.MakeConst( node.obj, node.left.conval, OPT.inttyp, reg );
Expr( node.right, expression );
OPC.SYSPutReg( expression, reg );
| sysnewfn :
Designator( node.left, designator );
OPL.LoadAdr( designator );
Expr( node.right, expression );
OPC.SYSNew( designator, expression );
| movefn :
Expr( node.left, sourceAdr );
Expr( node.right, destAdr );
Expr( node.right.link, expression );
OPC.SYSMove( destAdr, sourceAdr, expression );
| callfn : (*<<OJ*)
OPC.MakeConst( node.obj, node.left.conval, OPT.inttyp, reg );
Expr( node.right, expression );
OPC.SYSCall( expression, reg );
END; (* CASE *)
| Ncall :
IF ( node.left.obj # NIL ) & ( node.left.obj.mode = LProc ) & ( node.left.obj.mnolev > 0 ) THEN
psize := OPM.PointerSize; (* for static link *)
ELSE
psize := 0;
END;
AllocParams( node.obj, psize );
OPC.WriteStaticLink( node.left.obj );
AssignParams( node.obj, node.right );
Designator( node.left, procItem );
OPC.Call( procItem, node.left.obj );
OPC.AddToSP( psize );
| Nifelse :
IF ( node^.subcl # assertfn ) OR assert THEN IfStatement( node, FALSE ); END;
| Ncase :
CaseStatement( node );
| Nwhile :
begLabel := OPL.NewLabel;
OPL.DefineLabel( begLabel );
expression.tJump := OPL.NewLabel;
expression.fJump := OPL.NewLabel;
Expr( node.left, expression );
OPC.FalseJump( expression, expression.fJump );
StatSeq( node.right );
OPL.Jump( true, begLabel );
OPL.DefineLabel( expression.fJump );
| Nrepeat :
expression.tJump := OPL.NewLabel;
expression.fJump := OPL.NewLabel;
OPL.DefineLabel( expression.fJump );
StatSeq( node.left );
OPL.BegStat;
Expr( node.right, expression );
OPC.FalseJump( expression, expression.fJump );
| Nloop :
savedLoopEnd := loopEnd;
begLabel := OPL.NewLabel;
loopEnd := OPL.NewLabel;
OPL.DefineLabel( begLabel );
StatSeq( node.left );
OPL.Jump( true, begLabel );
OPL.DefineLabel( loopEnd );
loopEnd := savedLoopEnd;
| Nexit :
OPL.Jump( true, loopEnd );
| Nreturn :
IF node.left # NIL THEN
expression.tJump := OPL.NewLabel;
expression.fJump := OPL.NewLabel;
Expr( node.left, expression )
END;
OPC.Return( node.obj, node.left # NIL, expression );
| Nwith :
IfStatement( node, node.subcl = 0 );
| Ntrap :
IF node.right.conval.intval = 0 THEN node.right.conval.intval := 14 END ; (* should be parameter for front end*)
OPC.Trap( SHORT( node.right.conval.intval ) );
END; (* CASE *)
Checkpc;
node := node.link;
END; (* WHILE *)
END StatSeq;
PROCEDURE Module*( prog : OPT.Node );
BEGIN
StatSeq( prog )
END Module;
END OPV.